home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / printing / rotated thingies / Éusing rotate piccomments / rotn objs.p < prev   
Encoding:
Text File  |  2000-09-28  |  12.2 KB  |  493 lines

  1. {
  2.     File:        Rotn Objs.p
  3.  
  4.     Contains:    Rotn Objects demonstrates how to rotate objects on PostScript printers
  5.                  using the RotateBegin/End PicComments.  PrGeneral is used to change
  6.                 the resolution, which throws another wrench in the works; you have to
  7.                 scale everything.
  8.  
  9.     Written by: Dave Hersey    
  10.  
  11.     Copyright:    Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
  12.  
  13.                 You may incorporate this Apple sample source code into your program(s) without
  14.                 restriction. This Apple sample source code has been provided "AS IS" and the
  15.                 responsibility for its operation is yours. You are not permitted to redistribute
  16.                 this Apple sample source code as "Apple sample source code" after having made
  17.                 changes. If you're going to re-distribute the source, we require that you make
  18.                 it clear in the source that the code was descended from Apple sample source
  19.                 code, but that you've made changes.
  20.  
  21.     Change History (most recent first):
  22.                 7/26/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  23.                 
  24.  
  25. }
  26.  
  27. PROGRAM RotnObjects;
  28.  
  29. USES
  30.     Memory, QuickDraw, ToolUtils, Traps, Printing, Packages,Fonts,Devices;
  31.  
  32. CONST
  33.  
  34.     {The following constants are used to identify menus and their items. The menu IDs
  35.      have an "m" prefix and the item numbers within each menu have an "i" prefix.}
  36.  
  37.     rMenuBar    = 128;                    {menubar}
  38.  
  39.     mApple        = 128;                    {Apple menu}
  40.     iAbout        = 1;
  41.  
  42.     mFile        = 129;                    {File menu}
  43.     iPrint        = 1;
  44.     iQuit        = 3;
  45.  
  46.     mEdit        = 130;                    {Edit menu}
  47.  
  48.  
  49. VAR
  50.  
  51.     gQuitting    : Boolean;                {"Are we all done?" flag}
  52.  
  53.  
  54. {*------ RotateStuff -----------------------------------------------------------*}
  55.  
  56. {**
  57.  **      RotateStuff draws stuff rotated 45° using the RotateBegin/End PicComments.
  58.  **      The prRsl value passed is the resolution of the printer port.  This value
  59.  **      is used to scale all the graphics (text included) to the printer's
  60.  **      resolution.  We need to do this because we're changing resolution with
  61.  **      PrGeneral.
  62.  **}
  63.  
  64. {$S Main}
  65. PROCEDURE RotateStuff(prRsl : Integer);
  66.  
  67.     CONST
  68.         RotateBegin  = 200;
  69.         RotateEnd     = 201;
  70.         RotateCenter = 202;
  71.  
  72.     TYPE
  73.         rothdl         = ^rotptr;
  74.         rotptr         = ^trot;
  75.  
  76.         trot        = RECORD
  77.                             flip: integer;
  78.                             Angle: integer;
  79.                       END;     { trot }
  80.  
  81.         centhdl         = ^centptr;
  82.         centptr         = ^cent;
  83.         cent         = PACKED RECORD
  84.                             yInt: integer;
  85.                             yFrac: integer;
  86.                             xInt: integer;
  87.                             xFrac: integer;
  88.                       END;     { cent }
  89.  
  90.     VAR
  91.         rotation     : rothdl;
  92.         center        : centhdl;
  93.         where        : Point;
  94.         aRect        : Rect;
  95.         scalar        : Real;
  96.         fNum        : Integer;
  97.  
  98.     BEGIN
  99.         
  100.         scalar := prRsl;
  101.         scalar := scalar / 72;
  102.  
  103.     {Do a dummy draw to set the clipping region.}
  104.  
  105.         PenSize(0, 0);
  106.         MoveTo(0, 0);
  107.         LineTo(0, 0);
  108.         PenSize(1, 1);
  109.  
  110.         rotation := rothdl(NewHandle(SizeOf(trot)));
  111.         rotation^^.flip := 0; {no flip}
  112.         rotation^^.Angle := 45; {45 degree rotation}
  113.  
  114.         where.h := Round(100 * scalar);
  115.         where.v := Round(100 * scalar);
  116.         
  117.         center := centhdl(NewHandle(SizeOf(cent)));
  118.         center^^.xInt := where.h;  {center at where.}
  119.         center^^.yInt := where.v;
  120.         center^^.xFrac := 0;  {no fractional part}
  121.         center^^.yFrac := 0;
  122.         
  123.  
  124.     {Set the center of rotation.}
  125.  
  126.         PicComment(RotateCenter,GetHandleSize(handle(center)),handle(center));
  127.  
  128.     {Begin rotation.}
  129.  
  130.         PicComment(RotateBegin,GetHandleSize(handle(rotation)),handle(rotation));
  131.         MoveTo(where.h, where.v);
  132.  
  133.     {Draw rotated stuff.}
  134.  
  135.         GetFNum('Times', fNum);
  136.         TextFont(fNum);
  137.         TextSize(Round(24 * scalar));
  138.         DrawString('This text is rotated 45°…');
  139.  
  140.         SetRect(aRect, Round(200 * scalar), Round(150 * scalar), Round(300 * scalar), Round(250 * scalar));
  141.         FrameRect(aRect);
  142.  
  143.     {Rotation ends here.}
  144.  
  145.         PicComment(RotateEnd,0,NIL); {RotateEnd}
  146.         DisposeHandle(handle(rotation)); {Clean up}
  147.         DisposeHandle(handle(center));
  148.  
  149.     END;    {**  RotateStuff  **}
  150.  
  151.  
  152. {*------ DrawStuff -----------------------------------------------------------------*}
  153.  
  154. {**
  155.  **      DrawStuff draws the objects.  prRsl is the resolution of the printer's
  156.  **        GrafPort and is used to determine the amount to scale everything.
  157.  **}
  158.  
  159. {$S Main}
  160.  PROCEDURE DrawStuff(theGPort : GrafPtr; prRsl : Integer);
  161.  
  162.  VAR
  163.     oldPort        : GrafPtr;
  164.  
  165.  BEGIN
  166.  
  167. {Get the current port and save it, then rotate stuff and restore it.}
  168.     
  169.     GetPort(oldPort);
  170.     SetPort(theGPort);
  171.  
  172.     RotateStuff(prRsl);
  173.  
  174.     SetPort(oldPort);
  175.  
  176.  END;    {**  DrawStuff  **}
  177.  
  178.  
  179. {*------ GetBestRsl -----------------------------------------------------------------*}
  180.  
  181. {**
  182.  **      GetBestRsl determines the best "square" resolution supported by the printer.
  183.  **        For example, 300 dpi horizontal by 300 dpi vertical.  It isn't necessary to
  184.  **        use square resolutions, but it generally proves easier.  We use PrGeneral and
  185.  **        the getRslDataOp opCode to get a list of the supported resolutions for our
  186.  **        printer.  Then we just go through the rgRslRec and find the maximum square
  187.  **        resolution for discrete or non-discrete data, whichever we have.  Finally, we
  188.  **        make sure it's divisible by 72 for cleaner scaling.
  189.  **}
  190.  
  191. {$S Main}
  192. FUNCTION GetBestRsl :Integer;
  193.  
  194. VAR
  195.         err            : OSErr;
  196.         theRes, num    : Integer;
  197.         getRslData    : TGetRslBlk;
  198.  
  199. BEGIN
  200.  
  201. {Start off with our maximum resolution at 0, then call PrGeneral and parse our list
  202.  of returned values.}
  203.  
  204.         theRes := 0;
  205.         getRslData.iOpCode := getRslDataOp;
  206.  
  207.         PrGeneral(@getRslData);
  208.         err := getRslData.iError;
  209.  
  210. {If our printer only supports discrete resolutions, find the largest square one and
  211.  use that.  If our printer supports a range of resolutions, choose the smaller of the
  212.  maximum X and Y resolutions, then make it divisible by 72 for cleaner scaling.}
  213.  
  214.         IF (err = noErr) THEN
  215.             IF (getRslData.XRslRg.iMax = 0) AND (getRslData.YRslRg.iMax = 0) THEN
  216.                 BEGIN                                                                {Discrete resolutions.}
  217.                     FOR num := 1 TO getRslData.iRslRecCnt DO
  218.                         IF (getRslData.rgRslRec[num].iXRsl = getRslData.rgRslRec[num].iYRsl)
  219.                             AND (theRes < getRslData.rgRslRec[num].iXRsl) THEN
  220.                                 theRes := getRslData.rgRslRec[num].iXRsl;
  221.                 END
  222.             ELSE
  223.                 BEGIN                                                                {Variable resolutions.}
  224.                     IF (getRslData.XRslRg.iMax < getRslData.YRslRg.iMax) THEN
  225.                         theRes := (getRslData.XRslRg.iMax DIV 72) * 72            {Use multiple of 72 closest to max. X resolution.}
  226.                     ELSE
  227.                         theRes := (getRslData.YRslRg.iMax DIV 72) * 72            {Use multiple of 72 closest to max. Y resolution.}
  228.                 END;
  229.             
  230.  
  231. {In the unlikely event that PrGeneral fails and theRes is still 0, set it to 72.
  232.  This most likely is a supported resolution.  Finally return the best resolution we
  233.  could find.}
  234.  
  235.         IF theRes = 0 THEN theRes := 72;
  236.         GetBestRsl := theRes;
  237.  
  238. END;    {**  GetBestRsl  **}
  239.  
  240.  
  241. {*------ PrintStuff ----------------------------------------------------------------*}
  242. {**
  243.  **        PrintStuff will call all of the necessary Print Manager calls to print 
  244.  **        a document. It checks PrError after each Print Manager call. If an error 
  245.  **     is found, all of the Print Manager open calls (i.e. PrOpen, PrOpenDoc...) 
  246.  **        will have a corresponding close call before the error is posted to the user. 
  247.  **        You want to use this approach to make sure the Print Manager closes properly 
  248.  **        and all temporary memory is released.
  249.  **}
  250.  
  251. {$S Main}
  252. PROCEDURE PrintStuff;
  253.  
  254. VAR
  255.     oldPort          : GrafPtr;
  256.     thePrRecHdl        : THPrint;
  257.     thePrPort        : TPPrPort;
  258.     theStatus        : TPrStatus;
  259.     rslData            : TSetRslBlk;
  260.     err                : OSErr;
  261.     prRsl            : Integer;
  262.     bestRsl            : Integer;
  263.  
  264. BEGIN
  265.  
  266.  
  267. {Get our current port and create a print handle.  If no errors,
  268.  do our PrOpen call and, if no errors again, get the default
  269.  settings for the current driver.}
  270.  
  271.     GetPort(oldPort);
  272.     thePrRecHdl := THPrint(NewHandle(sizeof(TPrint)));
  273.     
  274.     IF (MemError = noErr) THEN
  275.     BEGIN
  276.         PrOpen;
  277.         IF (PrError = noErr) THEN
  278.         BEGIN
  279.             PrintDefault(thePrRecHdl);
  280.  
  281.             bestRsl := GetBestRsl;
  282.             rslData.iOpCode := SetRslOp;
  283.             rslData.hPrint := thePrRecHdl;
  284.             rslData.iXRsl := bestRsl;
  285.             rslData.iYRsl := bestRsl;
  286.             PrGeneral(@rslData);
  287.             err := rslData.iError;
  288.     
  289.             prRsl := bestRsl;
  290.  
  291.  
  292. {If we still have no errors, give style and print job dialogs, then open a
  293.  document and its page.  Keep checking for those dang printer errors.}
  294.  
  295.             IF (PrError = noErr) THEN
  296.             BEGIN
  297.                 IF (PrStlDialog(thePrRecHdl)) THEN
  298.                 BEGIN
  299.                     IF (PrJobDialog(thePrRecHdl)) THEN 
  300.                     BEGIN
  301.                         thePrPort := PrOpenDoc(thePrRecHdl, NIL, NIL);
  302.                                
  303.                         IF (PrError = noErr) THEN
  304.                         BEGIN
  305.                             PrOpenPage(thePrPort, NIL);
  306.  
  307.  
  308. {If we're still running error-free, draw our test page.  prRsl is the
  309.  resolution of our printer port.}
  310.  
  311.                             IF (PrError = noErr) THEN
  312.                                 DrawStuff(GrafPtr(thePrPort), prRsl);
  313.  
  314.  
  315. {When done, close our page and document and spool the document if necessary.  When
  316.  finshed, call PrClose to end the whole shabang.}
  317.  
  318.                             PrClosePage(thePrPort);
  319.                         END;
  320.                              
  321.                         PrCloseDoc(thePrPort);
  322.                              
  323.                         IF (thePrRecHdl^^.prJob.bJDocLoop = bSpoolLoop) and (PrError = noErr) THEN
  324.                             PrPicFile(thePrRecHdl, NIL, NIL, NIL, @theStatus);
  325.                     END;
  326.                 END;
  327.             END;
  328.         END;
  329.         
  330.         PrClose;
  331.  
  332.     END;
  333.  
  334. END;    {**  PrintStuff  **}
  335.  
  336.  
  337. {*------ Initialize ----------------------------------------------------------------*}
  338. {**
  339.  **        Initialize just handles necessary Toolbox initializing, setting our quitting 
  340.  **        flag to FALSE and installing our menus.
  341.  **}
  342.  
  343. {$S Initialize}
  344. PROCEDURE Initialize;
  345.  
  346. VAR
  347.     menuBar    : Handle;
  348.     
  349. BEGIN
  350.  
  351.     InitGraf(@qd.thePort);
  352.     InitFonts;
  353.     InitWindows;
  354.     InitMenus;
  355.     TEInit;
  356.     InitDialogs(NIL);
  357.     InitCursor;
  358.     FlushEvents(everyEvent, 0);    
  359.  
  360.     gQuitting := FALSE;
  361.  
  362.     menuBar := GetNewMBar(rMenuBar);        {read menus into menu bar}
  363.     IF (menuBar = NIL) THEN ExitToShell;    {should do real error stuff here.}
  364.     SetMenuBar(menuBar);                    {install menus}
  365.     DisposeHandle(menuBar);
  366.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');    {add DA names to Apple menu}
  367.     DrawMenuBar;
  368.  
  369. END;    {**  Initialize  **}
  370.  
  371.  
  372. {$S _DataInit}
  373. PROCEDURE _DataInit; EXTERNAL;
  374.  
  375. {This routine is automatically linked in by the MPW Linker. This external
  376.  reference to it is done so that we can unload its segment, %A5Init.}
  377.  
  378.  
  379. {*------ DoMenuCommand ----------------------------------------------------------------*}
  380. {**
  381.  **        DoMenuCommand is called when an item is chosen from the menu bar (after calling 
  382.  **        MenuSelect or MenuKey).  It does the right thing for each command.
  383.  **}
  384.  
  385. {$S Main}
  386. PROCEDURE DoMenuCommand(menuResult: LONGINT);
  387.  
  388. VAR
  389.     menuID, menuItem    : INTEGER;
  390.     daRefNum            : INTEGER;
  391.     daName                : Str255;
  392.  
  393. BEGIN
  394.  
  395. {Get the menu ID and item ID.}
  396.  
  397.     menuID := HiWrd(menuResult);
  398.     menuItem := LoWrd(menuResult);
  399.  
  400.     CASE menuID OF
  401.         mApple:
  402.             CASE menuItem OF
  403.                 iAbout:                {bring up alert for About}
  404.                     (* We do nothing here... *);
  405.  
  406.                 OTHERWISE
  407.                 BEGIN        {all non-About items in this menu are DAs}
  408.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  409.                     daRefNum := OpenDeskAcc(daName);
  410.                 END;
  411.             END;
  412.  
  413.         mFile:                            {File Menu}
  414.             CASE menuItem OF
  415.                 iPrint:                        {-> Print Test Page.}
  416.                     PrintStuff;
  417.                 iQuit:
  418.                     gQuitting := TRUE;        {-> Quit}
  419.             END;
  420.     END;        
  421.  
  422.     HiliteMenu(0);
  423.  
  424. END;    {**  DoMenuCommand  **}
  425.  
  426.  
  427. {*------ DoEvent ----------------------------------------------------------------*}
  428. {**
  429.  **        DoEvent handles incoming events for our app.  In this skimpy sample, we
  430.  **        only handle menu events and system clicks.
  431.  **}
  432.  
  433. {$S Main}
  434. PROCEDURE DoEvent;
  435.  
  436. VAR
  437.     part        : INTEGER;
  438.     key            : Char;
  439.     event        : EventRecord;
  440.     window        : WindowPtr;
  441.  
  442. BEGIN
  443.  
  444. {Repeatedly handle menu selecting events until our quit flag is set.}
  445.  
  446.     REPEAT
  447.         BEGIN
  448.             SystemTask;                                    {This must be called if using GetNextEvent}
  449.  
  450.             IF (GetNextEvent(everyEvent, event)) THEN
  451.                 CASE event.what OF
  452.                     mouseDown:
  453.                         BEGIN
  454.                             part := FindWindow(event.where, window);
  455.                             CASE part OF
  456.                                 inMenuBar:
  457.                                     DoMenuCommand(MenuSelect(event.where));
  458.                 
  459.                                 inSysWindow:
  460.                                     SystemClick(event, window);
  461.                             END;
  462.                         END;
  463.     
  464.                     keyDown, autoKey:
  465.                         BEGIN
  466.                             key := CHR(BAnd(event.message, charCodeMask));
  467.                             IF (BAnd(event.modifiers, cmdKey) <> 0) AND (event.what = keyDown) THEN
  468.                                 DoMenuCommand(MenuKey(key));
  469.                         END;
  470.                 END;
  471.         END;
  472.     UNTIL gQuitting;
  473.  
  474. END;    {**  DoEvent  **}
  475.  
  476.  
  477. {*------ Main ----------------------------------------------------------------*}
  478. {**
  479.  **        Main kickstarts our app.
  480.  **}
  481.  
  482. {$S Main}
  483. BEGIN
  484.  
  485.     {UnloadSeg(@_DataInit);    note that _DataInit must not be in Main!}
  486.     MaxApplZone;            {expand the heap so code segments load at the top}
  487.     Initialize;                {initialize the program}
  488.     {UnloadSeg(@Initialize);    note that Initialize must not be in Main!}
  489.     DoEvent;                {handle menu events until quitting.}
  490.  
  491. END.    {**  Rotn Objects.  **}
  492.  
  493.